package com.dreamchaser.familydevice.shiro.realm;


import com.alibaba.druid.util.StringUtils;
import com.dreamchaser.familydevice.dao.UserMapper;
import com.dreamchaser.familydevice.domain.dto.JwtAccountDTO;
import com.dreamchaser.familydevice.po.User;
import com.dreamchaser.familydevice.shiro.token.JwtToken;
import com.dreamchaser.familydevice.util.system.JsonWebTokenUtil;
import io.jsonwebtoken.CompressionException;
import io.jsonwebtoken.MalformedJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.data.redis.core.StringRedisTemplate;

/**
 * Jwt 验证规则
 * 经过拦截器拦截后，将所有的请求都需要走这个认证，来认证时候合法
 * <p>
 * 验证域
 *
 * @Description
 */
@Slf4j
public class JwtRealm extends AuthorizingRealm {

    private StringRedisTemplate stringRedisTemplate;
    private UserMapper userMapper;

    public JwtRealm(StringRedisTemplate stringRedisTemplate, UserMapper userMapper) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.userMapper = userMapper;
    }

    @Override
    public Class<?> getAuthenticationTokenClass() {
        // 此realm只支持jwtToken
        return JwtToken.class;
    }

    /**
     * 用于认证
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        if (!(authenticationToken instanceof JwtToken)) {
            return null;
        }
        JwtToken jwtToken = (JwtToken) authenticationToken;
        String jwt = (String) jwtToken.getCredentials();
        JwtAccountDTO jwtAccountDTO = null;
        User user;
        try {

            // 预先解析Payload
            // 没有做任何的签名校验
            jwtAccountDTO = JsonWebTokenUtil.parseJwt(jwt, JsonWebTokenUtil.SECRET_KEY);
            String token = stringRedisTemplate.opsForValue().get(jwtAccountDTO.getTokenId());
            if (StringUtils.isEmpty(token) || !token.equals(jwt)) {
                log.info("jwt:redis no jwt or errJwt");
                throw new MalformedJwtException("errJwt");
            }
            user = userMapper.selectByAccount(jwtAccountDTO.getSubject());
            if (user == null) {
                throw new UnknownAccountException();
            }
            if (jwtAccountDTO == null || jwtAccountDTO.getAccount() == null || StringUtils.isEmpty(jwtAccountDTO.getAccount().getMd5())) {
                throw new AuthenticationException("缺少md5");
            }
        } catch (MalformedJwtException e) {
            throw new AuthenticationException("errJwt");     //令牌格式错误
        } catch (CompressionException e) {
            throw new AuthenticationException("解压缩异常");     //解压缩异常
        }
        //  // 取消记住密码，取消session 所以set集合中只会有一个
        return new SimpleAuthenticationInfo(user.getPassword(), jwtAccountDTO.getAccount().getKey(), jwtAccountDTO.getAccount().getAccount());
    }

    /**
     * 用于授权
     * 从jwt中解析用户信息，并用于授权权限
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 解析JWT
        String jwt = (String) principalCollection.getPrimaryPrincipal();
//        JwtAccountVo jwtAccountVo = JsonWebTokenUtil.parseJwt(jwt, JsonWebTokenUtil.SECRET_KEY);
//        String permiess = stringRedisTemplate.opsForValue().get(RedisDataOptUtil.APP_AUTH_URL + jwtAccountVo.getTokenId());
//        if (StringUtils.isEmpty(permiess)) {
//            throw new ExpiredCredentialsException("");
//        }
//        Set<String> permissions = JsonWebTokenUtil.split(permiess);
//        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//        if (!CollectionUtils.isEmpty(permissions))
//            // 权限设置
//            info.setStringPermissions(permissions);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        return info;

    }

}
